/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { TypeNode, SyntaxKind, ArrayTypeNode, TypeReferenceNode } from 'ts-morph';
import { PropertyKind, TypeStructure, SerializerMetadata, TypeDependency } from '../Types';
import { ITypeHandler, TypeContext, ConversionDirection } from './ITypeHandler';
import { BaseTypeHandler } from './BaseTypeHandler';
import { CustomError, ErrorCodes } from '../utils/CustomError';
import { Logger } from '../logger/Logger';

abstract class GenericContainerHandler extends BaseTypeHandler implements ITypeHandler {
  abstract readonly name: string;
  abstract readonly kind: PropertyKind;
  abstract readonly typeNames: string[]; // 支持的类型名称，如 ['Array'], ['Map'], ['collections.Array']
  abstract readonly argsCount: 1 | 2; // 泛型参数数量

  readonly priority = 90; // 泛型容器优先级

  // ==================== 阶段1: 类型识别 ====================

  matches(typeNode: TypeNode): boolean {
    const syntaxKind = typeNode.getKind();

    // 支持数组字面量语法: T[]
    if (syntaxKind === SyntaxKind.ArrayType) {
      return this.kind === PropertyKind.ARRAY;
    }

    // 支持泛型语法: Array<T>, Map<K,V>, collections.Array<T>
    if (syntaxKind === SyntaxKind.TypeReference) {
      const typeRef = typeNode as TypeReferenceNode;
      const refName = typeRef.getTypeName().getText();
      return this.typeNames.includes(refName);
    }

    return false;
  }

  // ==================== 阶段2: 类型解析 ====================

  parse(typeNode: TypeNode, context: TypeContext): TypeStructure {
    const syntaxKind = typeNode.getKind();

    // 处理数组字面量: T[]
    if (syntaxKind === SyntaxKind.ArrayType) {
      return this.parseArrayLiteral(typeNode as ArrayTypeNode, context);
    }

    // 处理泛型语法: Array<T>, Map<K,V>
    if (syntaxKind === SyntaxKind.TypeReference) {
      return this.parseGenericType(typeNode as TypeReferenceNode, context);
    }

    throw new CustomError(`Unexpected syntax kind for ${this.name}: ${syntaxKind}`, ErrorCodes.UNEXPECTED_GENERIC);
  }

  /**
   * 解析数组字面量: T[]
   */
  private parseArrayLiteral(typeNode: ArrayTypeNode, context: TypeContext): TypeStructure {
    const elementTypeNode = typeNode.getElementTypeNode();

    Logger.debug('GenericHandler.parseArrayLiteral', typeNode.getText(), elementTypeNode.getText(), elementTypeNode.getKind());

    // 递归解析元素类型
    const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
    const elementType = TypeHandlerRegistry.getInstance().parseType(elementTypeNode, {
      ...context,
      depth: context.depth + 1
    });

    return {
      kind: this.kind,
      depth: context.depth,
      sourceText: typeNode.getText(),
      args: [elementType], // 使用args数组存储泛型参数
      dependencies: elementType.dependencies
    };
  }

  /**
   * 解析泛型类型: Array<T>, Map<K,V>
   */
  private parseGenericType(typeNode: TypeReferenceNode, context: TypeContext): TypeStructure {
    const typeArgs = typeNode.getTypeArguments();

    if (typeArgs.length !== this.argsCount) {
      throw new CustomError(
        `${this.name} expects ${this.argsCount} type argument(s), got ${typeArgs.length}`,
        ErrorCodes.GENERIC_NOT_MATCH
      );
    }

    // 收集所有依赖
    const allDependencies: TypeDependency[] = [];

    // 解析所有泛型参数
    const parsedArgs: TypeStructure[] = typeArgs.map((argNode) => {
      const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
      Logger.debug(`[GenericContainerHandler] parse: ${typeNode.getText()} -> ${typeNode.getKind()}`);
      const argStructure = TypeHandlerRegistry.getInstance().parseType(argNode, {
        ...context,
        depth: context.depth + 1
      });
      allDependencies.push(...argStructure.dependencies);
      return argStructure;
    });

    return {
      kind: this.kind,
      depth: context.depth,
      sourceText: typeNode.getText(),
      args: parsedArgs, // 使用args数组存储所有泛型参数
      dependencies: allDependencies
    };
  }

  // ==================== 阶段3: 序列化器配置 ====================

  getSerializerMetadata(structure: TypeStructure, withParam?: string): SerializerMetadata {
    const serializerName = this.getSerializerName();
    const defaultInstantiation = this.generateInstantiation(structure);

    return {
      name: serializerName,
      typeDeclaration: this.generateTypeDeclaration(structure),
      instantiationTemplate: this.applyWithParam(withParam, defaultInstantiation, structure),
      encodeMethod: 'encodeSerializableElement',
      decodeMethod: 'deserialize',
      decoderType: `${structure.sourceText} | undefined`,
      needsTypeAssertion: false
    };
  }

  // ==================== 阶段4: 代码生成 ====================

  generateInstantiation(structure: TypeStructure): string {
    if (!structure.args || structure.args.length !== this.argsCount) {
      throw new CustomError(
        `${this.name}: expected ${this.argsCount} type argument(s), got ${structure.args?.length || 0}`,
        ErrorCodes.GENERIC_NOT_MATCH
      );
    }

    if (this.argsCount === 1) {
      return this.generateSingleArgInstantiation(structure);
    } else {
      return this.generateDoubleArgInstantiation(structure);
    }
  }

  generateTypeDeclaration(structure: TypeStructure): string {
    if (!structure.args || structure.args.length !== this.argsCount) {
      throw new CustomError(
        `${this.name}: expected ${this.argsCount} type argument(s), got ${structure.args?.length || 0}`,
        ErrorCodes.GENERIC_NOT_MATCH
      );
    }

    if (this.argsCount === 1) {
      return this.generateSingleArgTypeDeclaration(structure);
    } else {
      return this.generateDoubleArgTypeDeclaration(structure);
    }
  }

  generateTypeKey(): string {
    return this.getTypeKeyString();
  }

  // ==================== Protected 抽象方法 - 子类必须实现 ====================

  /**
   * 生成类型键字符串（如 'array', 'set', 'map'）
   * 子类实现具体的类型键
   */
  protected abstract getTypeKeyString(): string;

  /**
   * 获取Sendable容器名称（如 'collections.Array', 'collections.Map'）
   * 子类可覆盖自定义Sendable容器名称
   */
  protected abstract getSendableContainerName(): string;

  // ==================== Protected 工具方法 - 子类可复用 ====================

  /**
   * 生成单参数容器的实例化代码
   * Array<T>, Set<T>, collections.Array<T>
   */
  protected generateSingleArgInstantiation(structure: TypeStructure): string {
    Logger.info(
      'generateSingleArgInstantiation: sourceText: %s, kind: %s, args: sourceText %s, kind: %s',
      structure.sourceText,
      structure.kind,
      structure.args.map((arg) => arg.sourceText).join(','),
      structure.args.map((arg) => arg.kind).join(',')
    );
    const serializerName = this.getSerializerName();
    const elementType = structure.args[0];
    const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
    const elementHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(elementType.kind);
    const elementSerializer = elementHandler.generateInstantiation(elementType);

    return `new ${serializerName}<${elementType.sourceText}>(${elementSerializer})`;
  }

  /**
   * 生成双参数容器的实例化代码
   * Map<K,V>, Record<K,V>, collections.Map<K,V>
   */
  protected generateDoubleArgInstantiation(structure: TypeStructure): string {
    Logger.info('generateDoubleArgInstantiation:', structure.sourceText, structure.kind, structure.args.join(','));
    const serializerName = this.getSerializerName();
    const keyType = structure.args[0];
    const valueType = structure.args[1];
    const { TypeHandlerRegistry } = require('./TypeHandlerRegistry');
    const keyHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(keyType.kind);
    const valueHandler = TypeHandlerRegistry.getInstance().getHandlerForKind(valueType.kind);
    const keySerializer = keyHandler.generateInstantiation(keyType);
    const valueSerializer = valueHandler.generateInstantiation(valueType);

    return `new ${serializerName}<${keyType.sourceText}, ${valueType.sourceText}>(${keySerializer}, ${valueSerializer})`;
  }

  /**
   * 生成单参数容器的类型声明
   * Array<T>, Set<T>, collections.Array<T>
   */
  protected generateSingleArgTypeDeclaration(structure: TypeStructure): string {
    const elementType = structure.args[0];
    const serializerName = this.getSerializerName();

    return `${serializerName}<${elementType.sourceText}>`;
  }

  /**
   * 生成双参数容器的类型声明
   * Map<K,V>, Record<K,V>, collections.Map<K,V>
   */
  protected generateDoubleArgTypeDeclaration(structure: TypeStructure): string {
    const keyType = structure.args[0];
    const valueType = structure.args[1];
    const serializerName = this.getSerializerName();

    return `${serializerName}<${keyType.sourceText}, ${valueType.sourceText}>`;
  }

  // ==================== Sendable转换 ====================

  generateSendableTypeDeclaration(structure: TypeStructure): string {
    if (!structure.args || structure.args.length !== this.argsCount) {
      throw new CustomError(
        `${this.name}: expected ${this.argsCount} type argument(s), got ${structure.args?.length || 0}`,
        ErrorCodes.GENERIC_NOT_MATCH
      );
    }

    // 递归获取TypeHandlerRegistry（通过全局单例）
    const registry = require('./TypeHandlerRegistry').TypeHandlerRegistry.getInstance();

    if (this.argsCount === 1) {
      // 单参数容器：Array<T> -> collections.Array<SendableT>
      const elementType = structure.args[0];
      const elementHandler = registry.getHandlerForKind(elementType.kind);
      const sendableElementType = elementHandler.generateSendableTypeDeclaration(elementType);
      return `${this.getSendableContainerName()}<${sendableElementType}>`;
    } else {
      // 双参数容器：Map<K,V> -> collections.Map<SendableK, SendableV>
      const keyType = structure.args[0];
      const valueType = structure.args[1];

      const keyHandler = registry.getHandlerForKind(keyType.kind);
      const valueHandler = registry.getHandlerForKind(valueType.kind);

      const sendableKeyType = keyHandler.generateSendableTypeDeclaration(keyType);
      const sendableValueType = valueHandler.generateSendableTypeDeclaration(valueType);

      return `${this.getSendableContainerName()}<${sendableKeyType}, ${sendableValueType}>`;
    }
  }

  generatePropertyConversion(_structure: TypeStructure, sourceValue: string, direction: ConversionDirection): string {
    if (direction === ConversionDirection.TO_SENDABLE) {
      // 普通容器 -> Sendable容器
      return this.generateToSendableConversion(sourceValue);
    } else {
      // Sendable容器 -> 普通容器
      return this.generateToOriginConversion(sourceValue);
    }
  }

  /**
   * 生成 TO_SENDABLE 转换代码
   * 子类可覆盖自定义转换逻辑
   */
  protected generateToSendableConversion(sourceValue: string): string {
    const sendableContainer = this.getSendableContainerName();

    if (this.argsCount === 1) {
      // Array/Set: new collections.Array(...this.items)
      return `new ${sendableContainer}(...${sourceValue})`;
    } else {
      // Map: new collections.Map(this.data.entries())
      return `new ${sendableContainer}(${sourceValue}.entries())`;
    }
  }

  /**
   * 生成 TO_ORIGIN 转换代码
   * 子类可覆盖自定义转换逻辑
   */
  protected generateToOriginConversion(sourceValue: string): string {
    const originContainer = this.getOriginContainerName();

    if (this.argsCount === 1) {
      // collections.Array/Set -> Array/Set: new Array(...this.items)
      return `new ${originContainer}(...${sourceValue})`;
    } else {
      // collections.Map -> Map: new Map(this.data.entries())
      return `new ${originContainer}(${sourceValue}.entries())`;
    }
  }

  /**
   * 获取原始容器名称（如 'Array', 'Map', 'Set'）
   * 子类可覆盖自定义原始容器名称
   */
  protected abstract getOriginContainerName(): string;
}

// ArrayHandler
class ArrayHandler extends GenericContainerHandler {
  readonly name = 'ArrayHandler';
  readonly kind = PropertyKind.ARRAY;
  readonly typeNames = ['Array'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'array'`;
  }

  protected getSerializerName(): string {
    return 'ArraySerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Array';
  }

  protected getOriginContainerName(): string {
    return 'Array';
  }
}

// MapHandler
class MapHandler extends GenericContainerHandler {
  readonly name = 'MapHandler';
  readonly kind = PropertyKind.MAP;
  readonly typeNames = ['Map'];
  readonly argsCount = 2 as const;

  protected getTypeKeyString(): string {
    return `'map'`;
  }

  protected getSerializerName(): string {
    return 'MapSerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Map';
  }

  protected getOriginContainerName(): string {
    return 'Map';
  }
}

// SetHandler
class SetHandler extends GenericContainerHandler {
  readonly name = 'SetHandler';
  readonly kind = PropertyKind.SET;
  readonly typeNames = ['Set'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'set'`;
  }

  protected getSerializerName(): string {
    return 'SetSerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Set';
  }

  protected getOriginContainerName(): string {
    return 'Set';
  }
}

// RecordHandler
class RecordHandler extends GenericContainerHandler {
  readonly name = 'RecordHandler';
  readonly kind = PropertyKind.RECORD;
  readonly typeNames = ['Record'];
  readonly argsCount = 2 as const;

  protected getTypeKeyString(): string {
    return `'map'`;
  }

  protected getSerializerName(): string {
    return 'RecordSerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Map';
  }

  protected getOriginContainerName(): string {
    return 'Map';
  }
}

// CollectionsArrayHandler
class CollectionsArrayHandler extends GenericContainerHandler {
  readonly name = 'CollectionsArrayHandler';
  readonly kind = PropertyKind.COLLECTIONS_ARRAY;
  readonly typeNames = ['collections.Array'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'array'`;
  }

  protected getSerializerName(): string {
    return 'CollectionsArraySerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Array';
  }

  protected getOriginContainerName(): string {
    return 'Array';
  }
}

// CollectionsSetHandler
class CollectionsSetHandler extends GenericContainerHandler {
  readonly name = 'CollectionsSetHandler';
  readonly kind = PropertyKind.COLLECTIONS_SET;
  readonly typeNames = ['collections.Set'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'set'`;
  }

  protected getSerializerName(): string {
    return 'CollectionsSetSerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Set';
  }

  protected getOriginContainerName(): string {
    return 'Set';
  }
}

// CollectionsMapHandler
class CollectionsMapHandler extends GenericContainerHandler {
  readonly name = 'CollectionsMapHandler';
  readonly kind = PropertyKind.COLLECTIONS_MAP;
  readonly typeNames = ['collections.Map'];
  readonly argsCount = 2 as const;

  protected getTypeKeyString(): string {
    return `'map'`;
  }

  protected getSerializerName(): string {
    return 'CollectionsMapSerializer';
  }

  protected getSendableContainerName(): string {
    return 'collections.Map';
  }

  protected getOriginContainerName(): string {
    return 'Map';
  }
}

class ArrayListHandler extends GenericContainerHandler {
  readonly name = 'ArrayListHandler';
  readonly kind = PropertyKind.ARRAY_LIST;
  readonly typeNames = ['ArrayList'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'ArrayList'`;
  }

  protected getSerializerName(): string {
    return 'ArrayListSerializer';
  }

  protected getSendableContainerName(): string {
    throw new CustomError('toSendable ArrayList type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }

  protected getOriginContainerName(): string {
    throw new CustomError('toOrgin ArrayList type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }
}

class HashMapHandler extends GenericContainerHandler {
  readonly name = 'HashMapHandler';
  readonly kind = PropertyKind.HASH_MAP;
  readonly typeNames = ['HashMap'];
  readonly argsCount = 2 as const;

  protected getTypeKeyString(): string {
    return `'HashMap'`;
  }

  protected getSerializerName(): string {
    return 'HashMapSerializer';
  }

  protected getSendableContainerName(): string {
    throw new CustomError('toSendable HashMap type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }

  protected getOriginContainerName(): string {
    throw new CustomError('toOrgin HashMap type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }
}

class HashSetHandler extends GenericContainerHandler {
  readonly name = 'HashSetHandler';
  readonly kind = PropertyKind.HASH_SET;
  readonly typeNames = ['HashSet'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'HashSet'`;
  }

  protected getSerializerName(): string {
    return 'HashSetSerializer';
  }

  protected getSendableContainerName(): string {
    throw new CustomError('toSendable HashSet type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }
  protected getOriginContainerName(): string {
    throw new CustomError('toOrgin HashSet type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }
}

class ListHandler extends GenericContainerHandler {
  readonly name = 'ListHandler';
  readonly kind = PropertyKind.LIST;
  readonly typeNames = ['List'];
  readonly argsCount = 1 as const;

  protected getTypeKeyString(): string {
    return `'List'`;
  }

  protected getSerializerName(): string {
    return 'ListSerializer';
  }

  protected getSendableContainerName(): string {
    throw new CustomError('toSendable List type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }

  protected getOriginContainerName(): string {
    throw new CustomError('toOrgin List type is not supported.', ErrorCodes.TYPE_NOT_SUPPORT);
  }
}

/**
 * 工厂函数：创建所有泛型容器Handler
 * @returns 7个泛型容器Handler实例
 */
export function createGenericContainerHandlers(): ITypeHandler[] {
  return [
    new ArrayHandler(),
    new SetHandler(),
    new MapHandler(),
    new RecordHandler(),
    new CollectionsArrayHandler(),
    new CollectionsSetHandler(),
    new CollectionsMapHandler(),
    new ArrayListHandler(),
    new HashMapHandler(),
    new HashSetHandler(),
    new ListHandler()
  ];
}
